home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_sun.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  10KB  |  547 lines

  1. /*
  2.  * @(#)plat_sun.c    1.8    2/24/94
  3.  *
  4.  * Sun-specific drive control routines.
  5.  */
  6. static char *ident = "@(#)plat_sun.c    1.8 2/24/94";
  7.  
  8. #ifdef sun
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17.  
  18. #include <ustat.h>
  19. #include <unistd.h>
  20. #include <signal.h>
  21. #ifdef solbourne
  22. # include <mfg/dklabel.h>
  23. # include <mfg/dkio.h>
  24. # include <sys/unistd.h>
  25. # include <dev/srvar.h>
  26. #else /* A real Sun */
  27. # ifdef SYSV
  28. #  include <sys/cdio.h>
  29. #  include <sys/scsi/impl/uscsi.h>
  30. # else
  31. #  include <sys/buf.h>
  32. #  include <sun/dkio.h>
  33. #  include <scsi/targets/srdef.h>
  34. #  include <scsi/impl/uscsi.h>
  35. #  include <scsi/generic/commands.h>
  36. # endif
  37. #endif
  38.  
  39. #include "struct.h"
  40.  
  41. void *malloc();
  42. char *strchr();
  43.  
  44. int    min_volume = 128;
  45. int    max_volume = 255;
  46.  
  47. extern char    *cd_device;
  48. extern int    intermittent_dev, keep_open;
  49.  
  50. /*
  51.  * find_cdrom
  52.  *
  53.  * Determine the name of the CD-ROM device.
  54.  *
  55.  * Use the first of /vol/dev/aliases/cdrom0, /dev/rdsk/c0t6d0s2, and /dev/rsr0
  56.  * that exists.  (Check for /vol/dev/aliases, not cdrom0, since it won't be
  57.  * there if there's no CD in the drive.)  This is done so a single SunOS 4.x
  58.  * binary can be used on any 4.x or higher Sun system.
  59.  */
  60. void
  61. find_cdrom()
  62. {
  63.     if (access("/vol/dev/aliases", X_OK) == 0)
  64.     {
  65.         /* Volume manager.  Device might not be there. */
  66.         intermittent_dev = 1;
  67.         cd_device = "/vol/dev/aliases/cdrom0";
  68.     }
  69.     else if (access("/dev/rdsk/c0t6d0s2", F_OK) == 0)
  70.     {
  71.         /* Solaris 2.x w/o volume manager.  Run keep_cd_open(). */
  72.         keep_open = 1;
  73.         cd_device = "/dev/rdsk/c0t6d0s2";
  74.     }
  75.     else if (access("/dev/rsr0", F_OK) == 0)
  76.         cd_device = "/dev/rsr0";
  77.     else
  78.     {
  79.         fprintf(stderr, "Couldn't find a CD device!\n");
  80.         exit(1);
  81.     }
  82. }
  83.  
  84. /*
  85.  * Initialize the drive.  A no-op for the generic driver.
  86.  */
  87. int
  88. gen_init(d)
  89.     struct wm_drive    *d;
  90. {
  91.     return (0);
  92. }
  93.  
  94. /*
  95.  * Get the number of tracks on the CD.
  96.  */
  97. int
  98. gen_get_trackcount(d, tracks)
  99.     struct wm_drive    *d;
  100.     int        *tracks;
  101. {
  102.     struct cdrom_tochdr    hdr;
  103.  
  104.     if (ioctl(d->fd, CDROMREADTOCHDR, &hdr))
  105.         return (-1);
  106.     
  107.     *tracks = hdr.cdth_trk1;
  108.     return (0);
  109. }
  110.  
  111. /*
  112.  * Get the start time and mode (data or audio) of a track.
  113.  */
  114. int
  115. gen_get_trackinfo(d, track, data, startframe)
  116.     struct wm_drive    *d;
  117.     int        track, *data, *startframe;
  118. {
  119.     struct cdrom_tocentry    entry;
  120.  
  121.     entry.cdte_track = track;
  122.     entry.cdte_format = CDROM_MSF;
  123.  
  124.     if (ioctl(d->fd, CDROMREADTOCENTRY, &entry))
  125.         return (-1);
  126.     
  127.     *startframe =    entry.cdte_addr.msf.minute * 60 * 75 +
  128.             entry.cdte_addr.msf.second * 75 +
  129.             entry.cdte_addr.msf.frame;
  130.     *data = entry.cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0;
  131.     
  132.     return (0);
  133. }
  134.  
  135. /*
  136.  * Get the number of frames on the CD.
  137.  */
  138. int
  139. gen_get_cdlen(d, frames)
  140.     struct wm_drive    *d;
  141.     int        *frames;
  142. {
  143.     int        tmp;
  144.  
  145.     return (gen_get_trackinfo(d, CDROM_LEADOUT, &tmp, frames));
  146. }
  147.  
  148.  
  149. /* Alarm signal handler. */
  150. static void do_nothing(x) int x; { x++; }
  151.  
  152. /*
  153.  * Get the current status of the drive: the current play mode, the absolute
  154.  * position from start of disc (in frames), and the current track and index
  155.  * numbers if the CD is playing or paused.
  156.  */
  157. int
  158. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  159.     struct wm_drive    *d;
  160.     enum cd_modes    oldmode, *mode;
  161.     int        *pos, *track, *index;
  162. {
  163.     struct cdrom_subchnl        sc;
  164.     struct itimerval        old_timer, new_timer;
  165.     struct sigaction        old_sig, new_sig;
  166.  
  167.     /* If we can't get status, the CD is ejected, so default to that. */
  168.     *mode = EJECTED;
  169.  
  170.     /* Is the device open? */
  171.     if (d->fd < 0)
  172.     {
  173.         switch (wmcd_open(d)) {
  174.         case -1:    /* error */
  175.             return (-1);
  176.  
  177.         case 1:        /* retry */
  178.             return (0);
  179.         }
  180.     }
  181.  
  182.     /*
  183.      * Solaris 2.2 hangs on this ioctl if someone else ejects the CD.
  184.      * So we schedule a signal to break out of the hang if the call
  185.      * takes an unreasonable amount of time.  The signal handler and
  186.      * timer are restored immediately to avoid interfering with XView.
  187.      */
  188.     if (intermittent_dev)
  189.     {
  190.         /*
  191.          * First clear out the timer so XView's signal doesn't happen
  192.          * while we're diddling with the signal handler.
  193.          */
  194.         timerclear(&new_timer.it_interval);
  195.         timerclear(&new_timer.it_value);
  196.         setitimer(ITIMER_REAL, &new_timer, &old_timer);
  197.  
  198.         /*
  199.          * Now install the no-op signal handler.
  200.          */
  201.         new_sig.sa_handler = do_nothing;
  202.         memset(&new_sig.sa_mask, 0, sizeof(new_sig.sa_mask));
  203.         new_sig.sa_flags = 0;
  204.         if (sigaction(SIGALRM, &new_sig, &old_sig))
  205.             perror("sigaction");
  206.  
  207.         /*
  208.          * And finally, set the timer.
  209.          */
  210.         new_timer.it_value.tv_sec = 2;
  211.         setitimer(ITIMER_REAL, &new_timer, NULL);
  212.     }
  213.  
  214.     sc.cdsc_format = CDROM_MSF;
  215.  
  216.     if (ioctl(d->fd, CDROMSUBCHNL, &sc))
  217.     {
  218.         if (intermittent_dev)
  219.         {
  220.             sigaction(SIGALRM, &old_sig, NULL);
  221.             setitimer(ITIMER_REAL, &old_timer, NULL);
  222.  
  223.             /* If the device can disappear, let it do so. */
  224.             close(d->fd);
  225.             d->fd = -1;
  226.         }
  227.  
  228.         return (0);
  229.     }
  230.  
  231.     if (intermittent_dev)
  232.     {
  233.         sigaction(SIGALRM, &old_sig, NULL);
  234.         setitimer(ITIMER_REAL, &old_timer, NULL);
  235.     }
  236.  
  237.     switch (sc.cdsc_audiostatus) {
  238.     case CDROM_AUDIO_PLAY:
  239.         *mode = PLAYING;
  240.         *track = sc.cdsc_trk;
  241.         *index = sc.cdsc_ind;
  242.         *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
  243.             sc.cdsc_absaddr.msf.second * 75 +
  244.             sc.cdsc_absaddr.msf.frame;
  245.         break;
  246.  
  247.     case CDROM_AUDIO_PAUSED:
  248.     case CDROM_AUDIO_INVALID:
  249.     case CDROM_AUDIO_NO_STATUS:
  250.         if (oldmode == PLAYING || oldmode == PAUSED)
  251.         {
  252.             *mode = PAUSED;
  253.             *track = sc.cdsc_trk;
  254.             *index = sc.cdsc_ind;
  255.             *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
  256.                 sc.cdsc_absaddr.msf.second * 75 +
  257.                 sc.cdsc_absaddr.msf.frame;
  258.         }
  259.         else
  260.             *mode = STOPPED;
  261.         break;
  262.  
  263.     /* CD ejected manually during play. */
  264.     case CDROM_AUDIO_ERROR:
  265.         break;
  266.  
  267.     case CDROM_AUDIO_COMPLETED:
  268.         *mode = TRACK_DONE; /* waiting for next track. */
  269.         break;
  270.  
  271.     default:
  272.         *mode = UNKNOWN;
  273.         break;
  274.     }
  275.  
  276.     return (0);
  277. }
  278.  
  279. /*
  280.  * Set the volume level for the left and right channels.  Their values
  281.  * range from 0 to 100.
  282.  */
  283. int
  284. gen_set_volume(d, left, right)
  285.     struct wm_drive    *d;
  286.     int        left, right;
  287. {
  288.     struct cdrom_volctrl v;
  289.  
  290.     left = (left * 255) / 100;
  291.     right = (right * 255) / 100;
  292.  
  293.     v.channel0 = left < 0 ? 0 : left > 255 ? 255 : left;
  294.     v.channel1 = right < 0 ? 0 : right > 255 ? 255 : right;
  295.  
  296.     return (ioctl(d->fd, CDROMVOLCTRL, &v));
  297. }
  298.  
  299. /*
  300.  * Pause the CD.
  301.  */
  302. int
  303. gen_pause(d)
  304.     struct wm_drive    *d;
  305. {
  306.     return (ioctl(d->fd, CDROMPAUSE));
  307. }
  308.  
  309. /*
  310.  * Resume playing the CD (assuming it was paused.)
  311.  */
  312. int
  313. gen_resume(d)
  314.     struct wm_drive    *d;
  315. {
  316.     return (ioctl(d->fd, CDROMRESUME));
  317. }
  318.  
  319. /*
  320.  * Stop the CD.
  321.  */
  322. int
  323. gen_stop(d)
  324.     struct wm_drive *d;
  325. {
  326.     return (ioctl(d->fd, CDROMSTOP));
  327. }
  328.  
  329. /*
  330.  * Play the CD from one position to another (both in frames.)
  331.  */
  332. int
  333. gen_play(d, start, end)
  334.     struct wm_drive    *d;
  335.     int        start, end;
  336. {
  337.     struct cdrom_msf        msf;
  338.  
  339.     msf.cdmsf_min0 = start / (60*75);
  340.     msf.cdmsf_sec0 = (start % (60*75)) / 75;
  341.     msf.cdmsf_frame0 = start % 75;
  342.     msf.cdmsf_min1 = end / (60*75);
  343.     msf.cdmsf_sec1 = (end % (60*75)) / 75;
  344.     msf.cdmsf_frame1 = end % 75;
  345.  
  346.     if (ioctl(d->fd, CDROMSTART))
  347.         return (-1);
  348.     if (ioctl(d->fd, CDROMPLAYMSF, &msf))
  349.         return (-2);
  350.     
  351.     return (0);
  352. }
  353.  
  354. /*
  355.  * Eject the current CD, if there is one.
  356.  */
  357. int
  358. gen_eject(d)
  359.     struct wm_drive    *d;
  360. {
  361.     struct stat    stbuf;
  362.     struct ustat    ust;
  363.  
  364.     if (fstat(d->fd, &stbuf) != 0)
  365.         return (-2);
  366.  
  367.     /* Is this a mounted filesystem? */
  368.     if (ustat(stbuf.st_rdev, &ust) == 0)
  369.         return (-3);
  370.  
  371.     if (ioctl(d->fd, CDROMEJECT))
  372.         return (-1);
  373.  
  374.     /* Close the device if it needs to vanish. */
  375.     if (intermittent_dev)
  376.     {
  377.         close(d->fd);
  378.         d->fd = -1;
  379.     }
  380.  
  381.     return (0);
  382. }
  383.  
  384. /*
  385.  * Keep the CD open all the time.
  386.  */
  387. void
  388. keep_cd_open()
  389. {
  390.     int    fd;
  391.     struct flock    fl;
  392.     extern    end;
  393.  
  394.     for (fd = 0; fd < 256; fd++)
  395.         close(fd);
  396.  
  397.     if (fork())
  398.         exit(0);
  399.  
  400.     if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0)
  401.         exit(0);
  402.     fl.l_type = F_WRLCK;
  403.     fl.l_whence = 0;
  404.     fl.l_start = 0;
  405.     fl.l_len = 0;
  406.     if (fcntl(fd, F_SETLK, &fl) < 0)
  407.         exit(0);
  408.  
  409.     if (open(cd_device, 0) >= 0)
  410.     {
  411.         brk(&end);
  412.         pause();
  413.     }
  414.  
  415.     exit(0);
  416. }
  417.  
  418. /*
  419.  * Read the initial volume from the drive, if available.  Each channel
  420.  * ranges from 0 to 100, with -1 indicating data not available.
  421.  */
  422. int
  423. gen_get_volume(d, left, right)
  424.     struct wm_drive    *d;
  425.     int        *left, *right;
  426. {
  427.     *left = *right = -1;
  428.  
  429.     return (wm_scsi2_get_volume(d, left, right));
  430. }
  431.  
  432. #ifndef solbourne
  433. /*
  434.  * Send an arbitrary SCSI command out the bus and optionally wait for
  435.  * a reply if "retbuf" isn't NULL.
  436.  */
  437. int
  438. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  439.     struct wm_drive    *d;
  440.     unsigned char    *cdb;
  441.     int        cdblen;
  442.     void        *retbuf;
  443.     int        retbuflen;
  444.     int        getreply;
  445. {
  446.     char            x;
  447.     struct uscsi_cmd    cmd;
  448.  
  449.     memset(&cmd, 0, sizeof(cmd));
  450.     cmd.uscsi_cdb = (void *) cdb;
  451.     cmd.uscsi_cdblen = cdblen;
  452.     cmd.uscsi_bufaddr = retbuf ? retbuf : (void *)&x;
  453.     cmd.uscsi_buflen = retbuf ? retbuflen : 0;
  454.     cmd.uscsi_flags = USCSI_ISOLATE | USCSI_SILENT;
  455.     if (getreply)
  456.         cmd.uscsi_flags |= USCSI_READ;
  457.     
  458.     if (ioctl(d->fd, USCSICMD, &cmd))
  459.         return (-1);
  460.     
  461.     if (cmd.uscsi_status)
  462.         return (-1);
  463.     
  464.     return (0);
  465. }
  466. #else
  467.  
  468. int wm_scsi() { return (-1); }
  469.  
  470. #endif
  471.  
  472. /*
  473.  * Open the CD device and figure out what kind of drive is attached.
  474.  */
  475. int
  476. wmcd_open(d)
  477.     struct wm_drive    *d;
  478. {
  479.     int        fd;
  480.     static int    warned = 0;
  481.     char        vendor[32], model[32], rev[32];
  482.  
  483.     if (cd_device == NULL)
  484.         find_cdrom();
  485.  
  486.     if (d->fd >= 0)        /* Device already open? */
  487.         return (0);
  488.     
  489.     d->fd = open(cd_device, 0);
  490.     if (d->fd < 0)
  491.     {
  492.         /* Solaris 2.2 volume manager moves links around */
  493.         if (errno == ENOENT && intermittent_dev)
  494.             return (1);
  495.  
  496.         if (errno == EACCES)
  497.         {
  498.             if (!warned)
  499.             {
  500.                 char    realname[MAXPATHLEN];
  501.  
  502.                 if (realpath(cd_device, realname) == NULL)
  503.                 {
  504.                     perror("realpath");
  505.                     return (-1);
  506.                 }
  507.  
  508.                 fprintf(stderr,
  509.         "As root, please run\n\nchmod 666 %s\n\n%s\n", realname,
  510.         "to give yourself permission to access the CD-ROM device.");
  511.                 warned++;
  512.             }
  513.         }
  514.         else if (errno != ENXIO)
  515.         {
  516.             perror(cd_device);
  517.             exit(1);
  518.         }
  519.  
  520.         /* No CD in drive. */
  521.         return (1);
  522.     }
  523.  
  524.     if (warned)
  525.     {
  526.         warned = 0;
  527.         fprintf(stderr, "Thank you.\n");
  528.     }
  529.  
  530.     /* Now fill in the relevant parts of the wm_drive structure. */
  531.     fd = d->fd;
  532.  
  533.     /* Can we figure out the drive type? */
  534.     vendor[0] = model[0] = rev[0] = '\0';
  535.     wm_scsi_get_drive_type(d, vendor, model, rev);
  536.  
  537.     *d = *(find_drive_struct(vendor, model, rev));
  538.     about_set_drivetype(d->vendor, d->model, rev);
  539.     d->fd = fd;
  540.  
  541.     (d->init)(d);
  542.  
  543.     return (0);
  544. }
  545.  
  546. #endif /* sun */
  547.